package cn.schoolwow.quickserver.response;

import cn.schoolwow.quickserver.domain.HttpResponseMeta;

import java.io.IOException;
import java.io.OutputStream;
import java.io.UnsupportedEncodingException;
import java.net.HttpCookie;
import java.nio.charset.Charset;
import java.time.LocalDateTime;
import java.time.format.DateTimeFormatter;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
import java.util.Locale;

public class HttpResponseImpl implements HttpResponse {
    private HttpResponseMeta httpResponseMeta;

    public HttpResponseImpl(HttpResponseMeta httpResponseMeta) {
        this.httpResponseMeta = httpResponseMeta;
    }

    @Override
    public void status(HttpStatus httpStatus) {
        httpResponseMeta.httpStatus(httpStatus);
    }

    @Override
    public void charset(String charset) {
        httpResponseMeta.charset = charset;
    }

    @Override
    public void addCookie(HttpCookie httpCookie) {
        StringBuilder builder = new StringBuilder(httpCookie.getName() + "=" + httpCookie.getValue() + ";");
        if (httpCookie.getMaxAge() > 0) {
            //expire为版本0,max-age为版本1
            String expires = LocalDateTime.now().plusSeconds(httpCookie.getMaxAge()).format(DateTimeFormatter.ofPattern("EEE, d MMM yyyy HH:mm:ss 'GMT'", Locale.US));
            builder.append(" expires=" + expires + ";");
        }
        if (null != httpCookie.getDomain()) {
            builder.append(" domain=" + httpCookie.getDomain() + ";");
        }
        if (null != httpCookie.getPath()) {
            builder.append(" path=" + httpCookie.getPath() + ";");
        }
        //TODO 以下注释内容加上会导致CookieManage报InvalidCookie警告,是判断没有=号造成的
//        if (httpCookie.getSecure()) {
//            builder.append(" secure;");
//        }
//        if (httpCookie.isHttpOnly()) {
//            builder.append(" httpOnly;");
//        }
        if (!httpResponseMeta.headers.containsKey("Set-Cookie")) {
            httpResponseMeta.headers.put("Set-Cookie", new ArrayList<>());
        }
        httpResponseMeta.headers.get("Set-Cookie").add(builder.toString());
    }

    @Override
    public List<String> getHeader(String name) {
        return httpResponseMeta.headers.get(name);
    }

    @Override
    public void addHeader(String name, String value) {
        if (!httpResponseMeta.headers.containsKey(name)) {
            httpResponseMeta.headers.put(name, new ArrayList<>());
        }
        httpResponseMeta.headers.get(name).add(value);
    }

    @Override
    public void setHeader(String name, String value) {
        httpResponseMeta.headers.put(name, new ArrayList<>(Arrays.asList(value)));
    }

    @Override
    public String getCharset() {
        return httpResponseMeta.charset;
    }

    @Override
    public void setCharset(String charset) {
        httpResponseMeta.charset = charset;
    }

    @Override
    public void setCharset(Charset charset) {
        httpResponseMeta.charset = charset.name();
    }

    @Override
    public void setContentLength(long contentLength) {
        httpResponseMeta.contentLength = contentLength;
    }

    @Override
    public String getContentType() {
        return httpResponseMeta.contentType;
    }

    @Override
    public void setContentType(String contentType) {
        httpResponseMeta.contentType = contentType;
    }

    @Override
    public String getContentDisposition() {
        List<String> values = getHeader("Content-Disposition");
        return values == null || values.size() == 0 ? null : values.get(0);
    }

    @Override
    public void setContentDisposition(String fileName) {
        try {
            String contentDisposition = "attachment;filename=" + new String(fileName.getBytes(), httpResponseMeta.charset);
            setHeader("Content-Disposition", contentDisposition);
        } catch (UnsupportedEncodingException e) {
            e.printStackTrace();
        }
    }

    @Override
    public void acceptRanges(boolean acceptRanges) {
        if (acceptRanges) {
            setHeader("Accept-Ranges", "bytes");
        } else {
            httpResponseMeta.headers.remove("Accept-Ranges");
        }
    }

    @Override
    public void streamingBody(String data) throws IOException {
        if (null == httpResponseMeta.headerString) {
            setContentType("text/plain");
            setHeader("Access-Control-Allow-Origin", "*");
            httpResponseMeta.fillHeadStream();
        }
        httpResponseMeta.outputStream.write(data.getBytes(httpResponseMeta.charset));
        httpResponseMeta.outputStream.flush();
    }

    @Override
    public void streamingBodyLine(String data) throws IOException {
        streamingBody(data+"\n");
    }

    @Override
    public void eventSource(EventSource eventSource) throws IOException {
        if (null == httpResponseMeta.headerString) {
            //发送头部
            setContentType("text/event-stream");
            setCharset("utf-8");
            httpResponseMeta.fillHeadStream();
        }
        String body = "id:" + eventSource.id + "\r\nevent:" + eventSource.event + "\r\nretry:" + eventSource.retry + "\r\ndata:" + eventSource.data + "\r\n\r\n";
        httpResponseMeta.outputStream.write(body.getBytes(httpResponseMeta.charset));
        httpResponseMeta.outputStream.flush();
    }

    @Override
    public OutputStream getOutputStream() throws IOException {
        if (null == httpResponseMeta.headerString) {
            httpResponseMeta.fillHeadStream();
        }
        return httpResponseMeta.outputStream;
    }
}
